#!/usr/bin/perl -wc

package RFCMail::ESMTP::Server::base;

use strict;
use warnings;
use RFCMail::ESMTP::Grammar::Base qw(MAILBOX_RE);
use RFCMail::ESMTP::Grammar::Parser qw(decode_string);
use RFCMail::ESMTP::Object::ReversePath qw(ReversePath);
use RFCMail::ESMTP::Object::ForwardPath qw(ForwardPath);
use RFCMail::ESMTP::Object::Parameters qw(Parameters);
use RFCMail::ESMTP::Object::Mailbox qw(Mailbox);


sub connect_handler {
    my ($self) = @_;
    return ([220, split(/\n+/, $self->{greeting})]);
}


sub ehlo_handler {
    my ($self, $cmd, $domain) = @_;
    $self->reset;
    $self->{state}->{Greeting} = $domain;
    $self->{state}->{Protocol} = $cmd eq "EHLO" ? "ESMTP" : "SMTP";
    return ([250, $self->{domain}.' '.$self->ehlo_greet,
	     ($cmd eq "EHLO" ? $self->ehlo_lines : () )
	    ]);
}


sub mail_handler {
    my ($self, $cmd, $path, $parm) = @_;
    my $state = $self->{state};
    # RFC 2821 4.1.4 puts certain requirements on the order of commands.
    return ([503, "You must say hello first"])
	if $state->state == 0;
    return ([503, "Transaction already started; issue RSET to start over"])
	if $state->state > 1;
    my $from = ReversePath($path);
    my $result = $self->mail_from($from, Parameters($parm));
    $state->{sender} = $from->reverse_path
	if $result->[0] == 250;
    return ($result);
}


sub rcpt_handler {
    my ($self, $cmd, $path, $parm) = @_;
    my $state = $self->{state};
    return ([503, "MAIL FROM: required first"])
	if $state->state < 2;
    my $to = ForwardPath($path);
    my $result = $self->rcpt_to($to, Parameters($parm));
    $self->rcpt_add($to)
	if $result->[0] =~ /^25./;
    return ($result);
}


sub data_handler {
    my ($self) = @_;
    my $result;
    return ([503, "MAIL FROM: required first"])
	if $self->{state}->state < 2;
    return ([554, "No valid recipients"])
	if $self->{state}->state < 3;
    $result = $self->data_start;
    if ($result->[0] == 354) {
	$self->{mode} = 'data_mode';
    }
    else {
        $self->data_abort;
    }
    return ($result);
}


sub rset_handler {
    $_[0]->reset;
    return ([250, "OK"]);
}


sub quit_handler { [221, "Service closing transmission channel"] }


sub vrfy_handler {
    my ($self, $cmd, $string) = @_;
    $string = decode_string($string);
    return ([250, "postmaster"])
	if $string =~ /\Apostmaster\Z/i;
    return ([553, "Not a valid mailbox name"])
	if $string !~ /\A@{[MAILBOX_RE]}\z/o;
    return ($self->vrfy_mailbox(Mailbox($string)));
}


sub no_handler { [502, "Command not implemented"] }


sub bad_seq_handler { [503, "Bad sequence of commands"] }


1;
